import utils from "./utils";
import Mask from "./mask";
import Line from "./line";
import Point from "./point";
import Label from "./label";
import Hammer from "hammerjs";
import Message from "./message";

/*
 * [
 *  {
 *      uuid: '',
 *      label: {x:0 , y:0, text: ''}
 *      color: 'red',
 *      points: [{x:0, y:0}],
 *      milestones: [{uuid: '', x:0, y:0, label: {x:0, y:0, text: ''}}]
 *  }
 *  ]
 */
export default function Map(canvasId, data) {
  this.canvasId = canvasId;
  this.drawing = null;
  this.data = data;
  this.lines = [];
  this.scale = { x: 1, y: 1 };
  this.translate = { x: 0, y: 0 };
  this.mask = new Mask(this);
  this.showMask = false;
  this.onMilestoneSelected = new Message();
  this.onPinch = new Message();
  this.onTap = new Message();
  this.rect = null;

  this.parse();

  if (this.canvasId) {
    this.mount(canvasId);
  }
}

Map.prototype.refresh = function() {
  this.lines.length = 0;
  this.resetState();
  this.parse();
  this.moveToCenter();
};

Map.prototype.resetState = function(){
    this.scale = { x: 1, y: 1 };
    this.translate = { x: 0, y: 0 };
    this.showMask = false;
};

Map.prototype.parse = function() {
  var self = this;
  var milestones = [];

  this.data.forEach(function(lineData) {
    var points = [];
    var milestones2 = [];

    lineData.points.forEach(function(pointData, index) {
      points.push(new Point(pointData.x, pointData.y, index));
    });

    var line = new Line(points, lineData.color);

    lineData.milestones.forEach(function(mileStoneData, index) {
      var milestone;
      var result = milestones.filter(function(item) {
        return item.label.text === mileStoneData.label.text;
      });

      if (result.length === 0) {
        milestone = new Point(
          mileStoneData.x,
          mileStoneData.y,
          index,
          mileStoneData.label.text
        );
        milestone.uuid = mileStoneData.uuid;
        milestone.metadata = mileStoneData.metadata;
        milestones.push(milestone);
      } else {
        milestone = result[0];
        milestone.setTransfer(true);
      }

      milestone.lines.push(line);
      milestones2.push(milestone);
    });

    var label = new Label(
      lineData.label.x,
      lineData.label.y,
      lineData.label.text
    );
    line.addLabel(label);
    line.milestones = milestones2;
    line.uuid = lineData.uuid;
    self.lines.push(line);
  });
};

Map.prototype.draw = function(context) {
  context.save();
  context.translate(this.translate.x, this.translate.y);
  context.scale(this.scale.x, this.scale.y);

  var selectedLines = [];

  this.lines.forEach(function(line) {
    if (line.isSelectd) {
      selectedLines.push(line);
    } else {
      line.draw(context);
    }
  });

  if (this.showMask) {
    this.mask.draw(context);
  }

  selectedLines.forEach(function(line) {
    line.draw(context);
  });

  context.restore();
};

Map.prototype.mount = function(id) {
  var self = this;
  var drawing = document.getElementById(id);
  var context = setupCanvas(drawing);
  var touch = utils.captureTouch(drawing);
  var mouse = utils.captureMouse(drawing);
  var hammertime = new Hammer(drawing);

  self.moveToCenter();

  hammertime.get("pinch").set({ enable: true });

  var pinchX, pinchY;
  hammertime.on("pinchstart", function() {
    pinchX = self.scale.x;
    pinchY = self.scale.y;
  });
  hammertime.on("pinchmove", function(e) {
    self.onPinch.fire(e);

    var pos = utils.getOffsetXY(drawing, e.center);
    var x = (pos.x - self.translate.x) / self.scale.x;
    var y = (pos.y - self.translate.y) / self.scale.y;

    self.scale.x = pinchX * e.scale;
    self.scale.y = pinchY * e.scale;

    self.translate.x = pos.x - x * self.scale.x;
    self.translate.y = pos.y - y * self.scale.y;
  });

  hammertime.on("tap", function(e) {
    self.onTap.fire(e);
  });

  var panX, panY;
  hammertime.on("panstart", function() {
    panX = self.translate.x;
    panY = self.translate.y;
  });
  hammertime.on("panmove", function(e) {
    self.translate.x = panX + e.deltaX;
    self.translate.y = panY + e.deltaY;
  });

  self.drawing = drawing;
  // touch.onMove.register(onMove);
  // mouse.onMove.register(onMove);
  mouse.onPick.register(onPick);
  mouse.onScale.register(onScale);

  function onMove(args) {
    if (args.isPressed) {
      self.translate.x += args.moveX;
      self.translate.y += args.moveY;
    }
  }

  function pickMileStone(p) {
    for (var i = 0; i < self.lines.length; i++) {
      var line = self.lines[i];
      var ms = line.milestones.filter(function(m) {
        return m.contains(p);
      });

      if (ms.length > 0) {
        return ms[0];
      }
    }

    return null;
  }

  function onPick(args) {
    var loc = args.getLocation(args.event);
    var p = {
      x: (loc.x - self.translate.x) / self.scale.x,
      y: (loc.y - self.translate.y) / self.scale.y
    };
    var m = pickMileStone(p);

    if (m != null) {
      self.onMilestoneSelected.fire(m);
      console.dir(m);
      return;
    }

    self.lines.forEach(function(line) {
      if (line.contains(p)) {
        line.isSelectd = true;
      } else {
        line.isSelectd = false;
      }
    });

    self.showMask = self.lines.some(function(line) {
      return line.isSelectd;
    });
  }

  function onScale(mouse, isUp) {
    var x = (mouse.x - self.translate.x) / self.scale.x;
    var y = (mouse.y - self.translate.y) / self.scale.y;

    if (isUp) {
      if (self.scale.x > 3) {
        return;
      }
      self.scale.x += 0.1;
      self.scale.y += 0.1;
    } else {
      if (self.scale.x < 0.4) {
        return;
      }
      self.scale.x -= 0.1;
      self.scale.y -= 0.1;
    }

    self.translate.x = mouse.x - x * self.scale.x;
    self.translate.y = mouse.y - y * self.scale.y;
  }

  function setupCanvas(canvas) {
    var ctx = canvas.getContext("2d");
    // Get the device pixel ratio, falling back to 1.
    var ratio = utils.getPixelRatio(ctx);
    // Get the size of the canvas in CSS pixels.
    var rect = canvas.getBoundingClientRect();
    self.rect = rect;
    // Give the canvas pixel dimensions of their CSS
    // size * the device pixel ratio.
    canvas.width = rect.width * ratio;
    canvas.height = rect.height * ratio;
    // Scale all drawing operations by the dpr, so you
    // don't have to worry about the difference.
    ctx.scale(ratio, ratio);
    return ctx;
  }

  (function draw() {
    context.clearRect(0, 0, drawing.width, drawing.height);
    self.draw(context);
    window.requestAnimationFrame(draw);
  })();
};

Map.prototype.getCenter = function(lines) {
    var self = this,
        left,
        right,
        top,
        bottom;

    var canvasCenter = {
        x: self.rect.width / 2,
        y: self.rect.height / 2
    };

    if (lines && lines.length) {
        lines.forEach(function (line) {
            line.points.forEach(function (p) {
                if (left == null) {
                    left = p;
                    right = p;
                    top = p;
                    bottom = p;
                } else {
                    if (p.x < left.x) {
                        left = p;
                    } else if (p.x > right.x) {
                        right = p;
                    }

                    if (p.y < top.y) {
                        top = p;
                    } else if (p.y > bottom.y) {
                        bottom = p;
                    }
                }
            });
        });

        if (left) {
            var mapCenter = {
                x: (left.x + right.x) / 2,
                y: (top.y + bottom.y) / 2
            };

            return {
                x: canvasCenter.x - mapCenter.x,
                y: canvasCenter.y - mapCenter.y
            };
        }
    }

    return canvasCenter;
};

Map.prototype.moveToCenter = function() {
    var self = this;
    var center = this.getCenter(self.lines);
    self.translate.x = center.x;
    self.translate.y =  center.y;
};

Map.prototype.selectLine = function (uuid) {
    var selected, self = this;
    this.resetState();
    this.lines.forEach(function (line) {
        line.isSelectd = (line.uuid === uuid);
        if(line.isSelectd){
            selected = line;
        }
    });
    this.showMask = true;
    if(selected){
        var center = this.getCenter([selected]);
        self.translate.x = center.x;
        self.translate.y =  center.y;
    }
};
